package com.cam.generator.web;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cam.framework.crud.CrudController;
import com.cam.framework.utils.RestResult;
import com.cam.generator.dict.GenVersion;
import com.cam.generator.dto.GenCodeDTO;
import com.cam.generator.entity.GenCode;
import com.cam.generator.service.GenCodeService;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("/generator/code")
public class GenCodeController extends CrudController {

    private final GenCodeService genCodeService;

    public GenCodeController(GenCodeService genCodeService) {
        this.genCodeService = genCodeService;
    }

    @GetMapping("/findById")
    public RestResult findById(@RequestParam String id) {
        GenCodeDTO genCodeDTO = genCodeService.findById(id);
        return RestResult.success().put("data", genCodeDTO);
    }

    @GetMapping("/page")
    public RestResult findPage(GenCode genCode, Page<GenCode> page) {
        return RestResult.success().put("page", genCodeService.page(page));
    }

    @PostMapping("/save")
    public RestResult save(@RequestBody GenCodeDTO genCodeDTO) {
        genCodeService.saveOrUpdate(genCodeDTO);
        return RestResult.success("保存数据成功").data(genCodeDTO).put("id", genCodeDTO.getId());
    }

    @GetMapping("/downloadForJeeplus8x")
    public ResponseEntity<byte[]> downloadForJeeplus9x(String id, HttpServletResponse response) throws IOException {
        GenCodeDTO genCodeDTO = genCodeService.findById(id);
        //            byte[] bytes = genCodeService.generateForJeeplus8x(id);

        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", String.format("attachment; filename=%s", genCodeDTO.getEntityName() + ".zip"));

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zipStream = new ZipOutputStream(outputStream);
        List<Map<String, String>> templateList = genCodeService.getTemplateListForJeeplus8x(genCodeDTO);
        VelocityContext velocityContext = genCodeService.prepareVelocityContext(genCodeDTO);
        for (Map<String, String> eachTemplateMap : templateList) {
            StringWriter eachSW = new StringWriter();
            Template template = Velocity.getTemplate(eachTemplateMap.get("templatePath"), Charset.defaultCharset().name());
            template.merge(velocityContext, eachSW);

            zipStream.putNextEntry(new ZipEntry(eachTemplateMap.get("categoryPath")));
            zipStream.write(eachSW.toString().getBytes(Charset.defaultCharset()));
            zipStream.closeEntry();
        }

        zipStream.close();
        return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_OCTET_STREAM).body(outputStream.toByteArray());
    }

    @GetMapping("/downloadForJeeplus9x")
    public ResponseEntity<byte[]> downloadForJeeplus9x(String id) throws IOException {
        GenCodeDTO genCodeDTO = genCodeService.findById(id);

        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", String.format("attachment; filename=%s", genCodeDTO.getEntityName() + ".zip"));

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zipStream = new ZipOutputStream(outputStream);
        List<Map<String, String>> templateList = genCodeService.getTemplateListForJeeplus9x(genCodeDTO);
        VelocityContext velocityContext = genCodeService.prepareVelocityContext(genCodeDTO);
        for (Map<String, String> eachTemplateMap : templateList) {
            StringWriter eachSW = new StringWriter();
            Template template = Velocity.getTemplate(eachTemplateMap.get("templatePath"), Charset.defaultCharset().name());
            template.merge(velocityContext, eachSW);

            zipStream.putNextEntry(new ZipEntry(eachTemplateMap.get("categoryPath")));
            zipStream.write(eachSW.toString().getBytes(Charset.defaultCharset()));
            zipStream.closeEntry();
        }

        zipStream.close();
        return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_OCTET_STREAM).body(outputStream.toByteArray());
    }

    @GetMapping("/downloadFor1x")
    public ResponseEntity<byte[]> downloadFor1x(String id) throws IOException {
        GenCodeDTO genCodeDTO = genCodeService.findById(id);

        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", String.format("attachment; filename=%s", genCodeDTO.getEntityName() + ".zip"));

        ByteArrayOutputStream outputStream = genCodeService.getDownloadOutputStream(genCodeDTO, GenVersion.CAM1X);
        return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_OCTET_STREAM).body(outputStream.toByteArray());

    }

    @GetMapping("/previewFor1x")
    public RestResult previewFor1x(String id) {
        List<Map<String, String>> result = genCodeService.getPreviewList(id, GenVersion.CAM1X);

        return RestResult.success().put("data", result);
    }

    @GetMapping("/downloadForIot1x")
    public ResponseEntity<byte[]> downloadForIot1x(String id) throws IOException {
        GenCodeDTO genCodeDTO = genCodeService.findById(id);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", String.format("attachment; filename=%s", genCodeDTO.getEntityName() + ".zip"));
        ByteArrayOutputStream outputStream = genCodeService.getDownloadOutputStream(genCodeDTO, GenVersion.IOT1X);
        return ResponseEntity.ok().headers(headers).contentType(MediaType.APPLICATION_OCTET_STREAM).body(outputStream.toByteArray());
    }

    @GetMapping("/previewForIot1x")
    public RestResult previewForIot1x(String id) {
        List<Map<String, String>> result = genCodeService.getPreviewList(id, GenVersion.IOT1X);
        return RestResult.success().put("data", result);
    }

    @GetMapping("/previewForJeeplus8x")
    public RestResult previewForJeeplus8x(String id) {
        GenCodeDTO genCodeDTO = genCodeService.findById(id);
        List<Map<String, String>> result = new ArrayList<>();
        VelocityContext velocityContext = genCodeService.prepareVelocityContext(genCodeDTO);

        List<Map<String, String>> templateList = genCodeService.getTemplateListForJeeplus8x(genCodeDTO);
        for (Map<String, String> eachTemplateMap : templateList) {
            StringWriter eachSW = new StringWriter();
            Template template = Velocity.getTemplate(eachTemplateMap.get("templatePath"), Charset.defaultCharset().name());
            template.merge(velocityContext, eachSW);
            result.add(new HashMap<String, String>(){{
                put("name", eachTemplateMap.get("categoryPath"));
                put("data", eachSW.toString());
            }});
        }

        return RestResult.success().put("data", result);
    }

    @GetMapping("/previewForJeeplus9x")
    public RestResult previewForJeeplus9x(String id) {
        GenCodeDTO genCodeDTO = genCodeService.findById(id);

        List<Map<String, String>> result = new ArrayList<>();
        VelocityContext velocityContext = genCodeService.prepareVelocityContext(genCodeDTO);

        // 获取templateList, 同时安排好打包路径
        List<Map<String, String>> templateList = genCodeService.getTemplateListForJeeplus9x(genCodeDTO);
        for (Map<String, String> eachTemplateMap : templateList) {
            StringWriter eachSW = new StringWriter();
            Template template = Velocity.getTemplate(eachTemplateMap.get("templatePath"), Charset.defaultCharset().name());
            template.merge(velocityContext, eachSW);
            result.add(new HashMap<String, String>(){{
                put("name", eachTemplateMap.get("categoryPath"));
                put("data", eachSW.toString());
            }});
        }

        return RestResult.success().put("data", result);
    }

}
